import { Injectable, ForbiddenException } from '@nestjs/common'
import { Model } from 'mongoose'
import { InjectModel } from '@nestjs/mongoose'
import { Menu } from './schemas/menu.schema'
import { MenuDto } from './dto/menu.dto'
import { CreateMenuDto } from './dto/create-menu.dto'
import { randomUUID } from 'node:crypto'
import { tree2Arr } from '../utils'
import { menus } from './data/menus'
import { UserDto } from 'src/users/dto/user.dto'
import { Role } from 'src/roles/schemas/role.schema'

@Injectable()
export class MenusService {
  constructor(
    @InjectModel(Menu.name) private menuModel: Model<Menu>,
    @InjectModel(Role.name) private roleModel: Model<Role>
  ) {
    this.initMenus()
  }

  async insertMany(Data: CreateMenuDto[]): Promise<any> {
    for (const item of Data) {
      const menuInfo = await this.menuModel
        .findOne({
          name: item.name
        })
        .exec()
      if (menuInfo) throw new ForbiddenException('菜单已存在')
      else {
        const menu: any = item
        if (!menu.id) menu.id = randomUUID()
      }
    }
    const createdMenu = this.menuModel.insertMany(Data)

    return createdMenu
  }

  async find(user?: UserDto): Promise<any> {
    if (user) {
      if (user.username == 'admin') return this.menuModel.find().exec()

      const roles = await this.roleModel
        .find({ id: { $in: user.roles } })
        .exec()

      const menusIds = [...new Set(roles.map((role) => role.menus).flat())]
      const menus = this.menuModel.find({ id: { $in: menusIds } }).exec()

      return menus
    }
  }

  async findOne(data: MenuDto): Promise<Menu | null> {
    return this.menuModel.findOne(data).exec()
  }

  async updateOne(data: any) {
    Reflect.deleteProperty(data, '_id')
    return this.menuModel.updateOne({ id: data.id }, { $set: data }).exec()
  }

  async deleteOne(data: any) {
    if (data) {
      const deletedMenu = await this.menuModel.deleteOne(data).exec()
      return deletedMenu
    }
  }

  async initMenus() {
    const menusInfo: any = await this.menuModel.find().exec()

    if (menusInfo.length === 0) {
      const data: any[] = []

      tree2Arr(menus, data)

      return await this.insertMany(data)
    } else return menusInfo
  }
}
